"""
股票涨跌趋势排行模块
提供通用的股票涨跌趋势排行和显示功能
"""

import time
import logging
from typing import Dict, List, Tuple, Optional
from dataclasses import dataclass
from enum import Enum
import re
from utils.price_formatter import format_price, format_change_percent

class TrendDirection(Enum):
    """趋势方向"""
    UP = "上涨"
    DOWN = "下跌"
    FLAT = "平盘"

class SortOrder(Enum):
    """排序方式"""
    DESC = "降序"  # 涨幅从大到小
    ASC = "升序"   # 跌幅从大到小

@dataclass
class StockTrendInfo:
    """股票趋势信息"""
    code: str
    name: str
    current_price: float
    yesterday_close: float
    change_amount: float
    change_percent: float
    volume: int
    turnover: float
    high: float
    low: float
    open: float
    trend_direction: TrendDirection
    
    def __post_init__(self):
        """计算趋势方向"""
        if self.change_percent > 0.1:
            self.trend_direction = TrendDirection.UP
        elif self.change_percent < -0.1:
            self.trend_direction = TrendDirection.DOWN
        else:
            self.trend_direction = TrendDirection.FLAT

class StockTrendRanker:
    """股票趋势排行器"""
    
    def __init__(self):
        self.logger = self._setup_logging()
    
    def _setup_logging(self) -> logging.Logger:
        """设置日志"""
        logger = logging.getLogger('StockTrendRanker')
        if not logger.handlers:
            handler = logging.StreamHandler()
            formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
            handler.setFormatter(formatter)
            logger.addHandler(handler)
            logger.setLevel(logging.INFO)
        return logger
    
    def analyze_trends(self, quotes_data: Dict) -> List[StockTrendInfo]:
        """分析股票趋势
        
        Args:
            quotes_data: 股票行情数据
            
        Returns:
            股票趋势信息列表
        """
        trends = []
        
        for code, data in quotes_data.items():
            try:
                # 从股票名称校对器获取正确名称
                stock_name = self._get_validated_name(code, data.get('name', f'股票{code}'))
                
                current_price = float(data['now'])
                yesterday_close = float(data['close'])
                
                # 跳过停牌或异常数据
                if current_price <= 0 or yesterday_close <= 0:
                    continue
                
                change_amount = current_price - yesterday_close
                change_percent = (change_amount / yesterday_close) * 100
                
                # 过滤异常涨跌幅
                if abs(change_percent) > 25:  # 涨跌超过25%的可能有问题
                    continue
                
                trend_info = StockTrendInfo(
                    code=code,
                    name=stock_name,
                    current_price=current_price,
                    yesterday_close=yesterday_close,
                    change_amount=change_amount,
                    change_percent=change_percent,
                    volume=int(data.get('turnover', 0)),
                    turnover=float(data.get('turnover', 0)),
                    high=float(data.get('high', current_price)),
                    low=float(data.get('low', current_price)),
                    open=float(data.get('open', current_price)),
                    trend_direction=TrendDirection.FLAT  # 将在__post_init__中计算
                )
                
                trends.append(trend_info)
                
            except (KeyError, ValueError, TypeError) as e:
                self.logger.warning(f"跳过无效数据: {code} - {e}")
                continue
        
        return trends
    
    def _get_validated_name(self, code: str, default_name: str) -> str:
        """获取校对后的股票名称"""
        try:
            from .stock_name_validator import get_stock_name_validator
            validator = get_stock_name_validator()
            result = validator.validate_stock_name(code)
            return result.name
        except:
            return default_name
    
    def sort_by_trend(self, trends: List[StockTrendInfo], 
                     sort_order: SortOrder = SortOrder.DESC) -> List[StockTrendInfo]:
        """按涨跌幅排序
        
        Args:
            trends: 股票趋势信息列表
            sort_order: 排序方式
            
        Returns:
            排序后的列表
        """
        return sorted(trends, 
                     key=lambda x: x.change_percent, 
                     reverse=(sort_order == SortOrder.DESC))
    
    def filter_by_direction(self, trends: List[StockTrendInfo], 
                          direction: TrendDirection) -> List[StockTrendInfo]:
        """按趋势方向筛选
        
        Args:
            trends: 股票趋势信息列表
            direction: 趋势方向
            
        Returns:
            筛选后的列表
        """
        return [trend for trend in trends if trend.trend_direction == direction]
    
    def get_top_gainers(self, trends: List[StockTrendInfo], top_n: int = 10) -> List[StockTrendInfo]:
        """获取涨幅榜
        
        Args:
            trends: 股票趋势信息列表
            top_n: 返回前N名
            
        Returns:
            涨幅榜
        """
        gainers = self.filter_by_direction(trends, TrendDirection.UP)
        sorted_gainers = self.sort_by_trend(gainers, SortOrder.DESC)
        return sorted_gainers[:top_n]
    
    def get_top_losers(self, trends: List[StockTrendInfo], top_n: int = 10) -> List[StockTrendInfo]:
        """获取跌幅榜
        
        Args:
            trends: 股票趋势信息列表
            top_n: 返回前N名
            
        Returns:
            跌幅榜
        """
        losers = self.filter_by_direction(trends, TrendDirection.DOWN)
        sorted_losers = self.sort_by_trend(losers, SortOrder.ASC)
        return sorted_losers[:top_n]
    
    def get_market_summary(self, trends: List[StockTrendInfo]) -> Dict:
        """获取市场概况
        
        Args:
            trends: 股票趋势信息列表
            
        Returns:
            市场概况数据
        """
        if not trends:
            return {}
        
        up_count = len(self.filter_by_direction(trends, TrendDirection.UP))
        down_count = len(self.filter_by_direction(trends, TrendDirection.DOWN))
        flat_count = len(self.filter_by_direction(trends, TrendDirection.FLAT))
        
        total_count = len(trends)
        avg_change_percent = sum(t.change_percent for t in trends) / total_count
        
        return {
            'total_stocks': total_count,
            'up_count': up_count,
            'down_count': down_count,
            'flat_count': flat_count,
            'up_ratio': up_count / total_count * 100,
            'down_ratio': down_count / total_count * 100,
            'avg_change_percent': avg_change_percent,
            'max_gain': max(trends, key=lambda x: x.change_percent).change_percent,
            'max_loss': min(trends, key=lambda x: x.change_percent).change_percent
        }
    
    def display_trend_ranking(self, trends: List[StockTrendInfo], 
                            title: str = "股票涨跌趋势排行",
                            show_count: int = 20,
                            show_summary: bool = True):
        """显示趋势排行
        
        Args:
            trends: 股票趋势信息列表
            title: 显示标题
            show_count: 显示数量
            show_summary: 是否显示市场概况
        """
        if not trends:
            print("❌ 没有获取到股票数据")
            return
        
        current_time = time.strftime('%Y-%m-%d %H:%M:%S')
        
        # 定义各列的宽度
        col_widths = {
            'rank': 4,
            'name': 12,
            'code': 8,
            'price': 10,
            'change': 14,
            'volume': 10,
            'amplitude': 8,
            'trend': 6
        }
        
        total_width = sum(col_widths.values()) + 7
        
        print(f"\n{'='*total_width}")
        print(f"📊 {title} TOP{min(show_count, len(trends))} - {current_time}")
        print(f"{'='*total_width}")
        
        # 显示市场概况
        if show_summary:
            summary = self.get_market_summary(trends)
            print(f"\n📈 市场概况:")
            print(f"   总股票数: {summary['total_stocks']} | 上涨: {summary['up_count']}({summary['up_ratio']:.1f}%) | "
                  f"下跌: {summary['down_count']}({summary['down_ratio']:.1f}%) | 平盘: {summary['flat_count']}")
            print(f"   平均涨跌: {summary['avg_change_percent']:+.2f}% | 最大涨幅: {summary['max_gain']:+.2f}% | "
                  f"最大跌幅: {summary['max_loss']:+.2f}%")
        
        # 打印表头
        header = (f"{self._pad_string('排名', col_widths['rank'])} "
                 f"{self._pad_string('股票名称', col_widths['name'])} "
                 f"{self._pad_string('代码', col_widths['code'])} "
                 f"{self._pad_string('现价', col_widths['price'], 'right')} "
                 f"{self._pad_string('涨跌幅', col_widths['change'], 'right')} "
                 f"{self._pad_string('成交量', col_widths['volume'], 'right')} "
                 f"{self._pad_string('振幅', col_widths['amplitude'], 'right')} "
                 f"{self._pad_string('趋势', col_widths['trend'])}")
        print(f"\n{header}")
        print("-" * total_width)
        
        # 显示股票数据
        for rank, trend in enumerate(trends[:show_count], 1):
            # 格式化价格显示（ETF显示3位小数，普通股票2位小数）
            price_str = format_price(trend.current_price, stock_code=trend.code, stock_name=trend.name)
            
            # 格式化涨跌幅显示（带颜色和趋势符号，智能小数位数）
            change_str = format_change_percent(trend.change_percent, stock_code=trend.code, stock_name=trend.name)
            if trend.change_percent > 0:
                colored_change = f"\033[31m📈{change_str}\033[0m"  # 红色上涨
                trend_emoji = "🔥" if trend.change_percent > 5 else "📈"
            elif trend.change_percent < 0:
                colored_change = f"\033[32m📉{change_str}\033[0m"  # 绿色下跌
                trend_emoji = "💧" if trend.change_percent < -5 else "📉"
            else:
                colored_change = f"⚪{change_str}"  # 平盘
                trend_emoji = "⚪"
            
            # 计算振幅（智能小数位数）
            amplitude = ((trend.high - trend.low) / trend.yesterday_close) * 100
            amplitude_str = format_change_percent(amplitude, stock_code=trend.code, stock_name=trend.name)
            
            # 格式化成交量
            volume_str = self._format_volume(trend.volume)
            
            # 趋势状态
            trend_status = trend_emoji
            
            # 打印数据行
            row = (f"{self._pad_string(str(rank), col_widths['rank'])} "
                  f"{self._pad_string(trend.name, col_widths['name'])} "
                  f"{self._pad_string(trend.code, col_widths['code'])} "
                  f"{self._pad_string(price_str, col_widths['price'], 'right')} "
                  f"{self._pad_string(colored_change, col_widths['change'], 'right')} "
                  f"{self._pad_string(volume_str, col_widths['volume'], 'right')} "
                  f"{self._pad_string(amplitude_str, col_widths['amplitude'], 'right')} "
                  f"{self._pad_string(trend_status, col_widths['trend'])}")
            print(row)
        
        print("-" * total_width)
        print(f"📊 共显示 {min(show_count, len(trends))} 只股票")
        print("趋势说明: 🔥强涨 📈上涨 ⚪平盘 📉下跌 💧重跌")
        print("颜色说明: \033[31m红色=上涨\033[0m, \033[32m绿色=下跌\033[0m")
    
    def display_gainers_and_losers(self, trends: List[StockTrendInfo], 
                                  top_n: int = 10):
        """显示涨跌幅双榜
        
        Args:
            trends: 股票趋势信息列表
            top_n: 每榜显示数量
        """
        print(f"\n{'='*120}")
        print(f"📊 A股涨跌双榜 TOP{top_n}")
        print(f"{'='*120}")
        
        gainers = self.get_top_gainers(trends, top_n)
        losers = self.get_top_losers(trends, top_n)
        
        # 并排显示
        print(f"{'🔥 涨幅榜':<58} {'💧 跌幅榜':<58}")
        print(f"{'-'*58} {'-'*58}")
        
        max_rows = max(len(gainers), len(losers))
        for i in range(max_rows):
            left_content = ""
            right_content = ""
            
            # 左侧涨幅榜
            if i < len(gainers):
                gainer = gainers[i]
                gainer_change_str = format_change_percent(gainer.change_percent, stock_code=gainer.code, stock_name=gainer.name)
                gainer_price_str = format_price(gainer.current_price, stock_code=gainer.code, stock_name=gainer.name)
                left_content = (f"{i+1:2d}. {gainer.name[:8]:<8}({gainer.code}) "
                              f"\033[31m{gainer_change_str}\033[0m ¥{gainer_price_str}")
            else:
                left_content = " " * 58
            
            # 右侧跌幅榜
            if i < len(losers):
                loser = losers[i]
                loser_change_str = format_change_percent(loser.change_percent, stock_code=loser.code, stock_name=loser.name)
                loser_price_str = format_price(loser.current_price, stock_code=loser.code, stock_name=loser.name)
                right_content = (f"{i+1:2d}. {loser.name[:8]:<8}({loser.code}) "
                               f"\033[32m{loser_change_str}\033[0m ¥{loser_price_str}")
            
            print(f"{left_content:<58} {right_content}")
        
        print(f"{'-'*58} {'-'*58}")
        
        # 显示统计信息
        summary = self.get_market_summary(trends)
        print(f"📈 涨停: {len([t for t in trends if t.change_percent >= 9.8])} | "
              f"跌停: {len([t for t in trends if t.change_percent <= -9.8])} | "
              f"活跃: {len([t for t in trends if abs(t.change_percent) >= 3])} | "
              f"上涨: {summary['up_count']}({summary['up_ratio']:.1f}%)")
    
    def _format_volume(self, volume: int) -> str:
        """格式化成交量显示"""
        if volume >= 100000000:  # 100M+
            return f"{volume/100000000:.1f}B"
        elif volume >= 1000000:  # 1M+
            return f"{volume/1000000:.1f}M"
        elif volume >= 1000:     # 1K+
            return f"{volume/1000:.1f}K"
        else:
            return str(volume)
    
    def _get_display_width(self, text: str) -> int:
        """计算字符串的显示宽度（考虑中文字符占用2个字符宽度，忽略ANSI颜色代码）"""
        # 移除ANSI颜色代码
        clean_text = re.sub(r'\033\[[0-9;]*m', '', text)
        
        width = 0
        for char in clean_text:
            if ord(char) > 127:  # 非ASCII字符（包括中文）
                width += 2
            else:
                width += 1
        return width
    
    def _pad_string(self, text: str, target_width: int, align: str = 'left') -> str:
        """根据显示宽度填充字符串到指定宽度"""
        # 移除ANSI颜色代码来计算实际显示宽度
        clean_text = re.sub(r'\033\[[0-9;]*m', '', text)
        current_width = self._get_display_width(clean_text)
        
        if current_width >= target_width:
            return text
        
        padding = target_width - current_width
        if align == 'left':
            return text + ' ' * padding
        elif align == 'right':
            return ' ' * padding + text
        else:  # center
            left_padding = padding // 2
            right_padding = padding - left_padding
            return ' ' * left_padding + text + ' ' * right_padding

def create_trend_ranker() -> StockTrendRanker:
    """创建股票趋势排行器实例"""
    return StockTrendRanker() 